//给你一个 m x n 的矩阵 board ，由若干字符 'X' 和 'O' ，找到所有被 'X' 围绕的区域，并将这些区域里所有的 'O' 用 'X' 填充
//。
//
// 
// 
// 
// 
// 
//
// 示例 1： 
// 
// 
//输入：board = [["X","X","X","X"],["X","O","O","X"],["X","X","O","X"],["X","O",
//"X","X"]]
//输出：[["X","X","X","X"],["X","X","X","X"],["X","X","X","X"],["X","O","X","X"]]
//解释：被围绕的区间不会存在于边界上，换句话说，任何边界上的 'O' 都不会被填充为 'X'。 任何不在边界上，或不与边界上的 'O' 相连的 'O' 最终都
//会被填充为 'X'。如果两个元素在水平或垂直方向相邻，则称它们是“相连”的。
// 
//
// 示例 2： 
//
// 
//输入：board = [["X"]]
//输出：[["X"]]
// 
//
// 
//
// 提示： 
//
// 
// m == board.length 
// n == board[i].length 
// 1 <= m, n <= 200 
// board[i][j] 为 'X' 或 'O' 
// 
//
// Related Topics 深度优先搜索 广度优先搜索 并查集 数组 矩阵 👍 1122 👎 0


package LeetCode.editor.cn;

import java.util.*;

/**
 * @author ldltd
 * @date 2024-05-17 22:39:06
 * @description 130.被围绕的区域
 */
public class SurroundedRegions{
	 public static void main(String[] args) {
	 	 //测试代码
	 	 SurroundedRegions fun=new SurroundedRegions();
	 	 Solution solution = fun.new Solution();

		 char[][] board = {
				 {'X', 'X', 'X', 'X'},
				 {'X', 'O', 'O', 'X'},
				 {'X', 'X', 'O', 'X'},
				 {'X', 'O', 'X', 'X'}

		 };
		 char[][] board1 = {
				 {'X', 'O', 'X'},
				 {'O', 'X', 'O'},
				 {'X', 'O', 'X'}

		 };
		 solution.solve(board1);
	 }
	 
//力扣代码
//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
		 int []dx={0,-1,1,0,0};
		 int []dy={0,0,0,-1,1};
    public void solve1(char[][] board) {
		boolean[][] vis=new boolean[board.length][board[0].length];
		Set<Integer[]> t=new HashSet<>();

		Deque<Integer[]> q=new ArrayDeque<>();
		for (int i = 0; i < board.length; i++) {
			for (int j = 0; j < board[0].length; j++) {
				boolean flag=false;
				if(!vis[i][j]&&board[i][j]=='O'){
					q.offer(new Integer[]{i,j});
					while (!q.isEmpty()){
						Integer[] poll = q.poll();
						for (int k = 0; k < 5; k++) {
							int x=poll[0]+dx[k];
							int y=poll[1]+dy[k];
							if(x>=0&&y>=0&&x<board.length&&y<board[0].length&&board[x][y]=='O'){
								if(x==board.length-1||y==board[0].length-1||x==0||y==0){
									flag=true;
								}
								 if(!vis[x][y]){
									q.offer(new Integer[]{x,y});
								}
								t.add(new Integer[]{x,y});
								vis[x][y]=true;
							}

						}
					}
					if(!flag){
						for (Integer[] ind : t) {
								board[ind[0]][ind[1]]='X';
						}
					}
					t.clear();
				}
			}
		}
    }
	public void solve(char[][] board) {
		n=board.length;
		if(n==0) return;
		m=board[0].length;
		//从每个边界出发，先从左右两列开始
		for (int i = 0; i < n; i++) {
			dfs(board,i,0);
			dfs(board,i,m-1);
		}
		//再从上下两行去掉重复的刚刚
		for (int i = 1; i < m-1; i++) {
			dfs(board,0,i);
			dfs(board,n-1,i);
		}
		//依次遍历，如果已经遍历过了，把他复原成O
		//说明和边界相通，其余的都会被染成X
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				if (board[i][j] == 'A') {
					board[i][j]='O';
				}else if(board[i][j]=='O'){
					board[i][j]='X';
				}
			}
		}
	}
	int n,m;
	public void  dfs(char [][]board,int x,int y){
		if (x < 0 || x >= n || y < 0 || y >= m || board[x][y] != 'O') {
			return;
		}
		board[x][y] = 'A';
		dfs(board, x + 1, y);
		dfs(board, x - 1, y);
		dfs(board, x, y + 1);
		dfs(board, x, y - 1);
	}


	int[] dx1 = {1, -1, 0, 0};
	int[] dy1 = {0, 0, 1, -1};
	/*广度优先*/
	public void solve2(char[][] board) {
		int n = board.length;
		if (n == 0) {
			return;
		}
		int m = board[0].length;
		Queue<int[]> queue = new LinkedList<int[]>();
		//把边界上所有的O加入队列，并修改为A
		for (int i = 0; i < n; i++) {
			if (board[i][0] == 'O') {
				queue.offer(new int[]{i, 0});
				board[i][0] = 'A';
			}
			if (board[i][m - 1] == 'O') {
				queue.offer(new int[]{i, m - 1});
				board[i][m - 1] = 'A';
			}
		}
		for (int i = 1; i < m - 1; i++) {
			if (board[0][i] == 'O') {
				queue.offer(new int[]{0, i});
				board[0][i] = 'A';
			}
			if (board[n - 1][i] == 'O') {
				queue.offer(new int[]{n - 1, i});
				board[n - 1][i] = 'A';
			}
		}
		//依次遍历每一个边界上的A
		while (!queue.isEmpty()) {
			int[] cell = queue.poll();
			int x = cell[0], y = cell[1];
			for (int i = 0; i < 4; i++) {
				//遍历几个方向
				int mx = x + dx1[i], my = y + dy1[i];
				if (mx < 0 || my < 0 || mx >= n || my >= m || board[mx][my] != 'O') {
					continue;
				}
				//如果是0就加入队列，并修改为A
				queue.offer(new int[]{mx, my});
				board[mx][my] = 'A';
			}
		}
		//同样把没有感染的修改为X，感染的修改为O
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				if (board[i][j] == 'A') {
					board[i][j] = 'O';
				} else if (board[i][j] == 'O') {
					board[i][j] = 'X';
				}
			}
		}
	}

}
//leetcode submit region end(Prohibit modification and deletion)

}
